# -*- python -*-
# ex: set syntax=python:

# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# READ THIS:
# See http://dev.chromium.org/developers/testing/chromium-build-infrastructure

import os

# These modules come from scripts, which must be in the PYTHONPATH.
from master import master_utils
from master import slaves_list
from common import chromium_utils
from master.builders_pools import BuildersPools
from master.factory import annotator_factory
from master.try_job_http import TryJobHTTP

from buildbot.scheduler import Triggerable

import config
import master_site_config

ActiveMaster = master_site_config.NativeClientTryServer

nacl_source_url = (
    'https://chromium.googlesource.com/native_client/src/native_client')

MAIL_NOTIFIER = True

# This is the dictionary that the buildmaster pays attention to. We also use
# a shorter alias to save typing.
c = BuildmasterConfig = {}

config.DatabaseSetup(c)

####### CHANGESOURCES

c['change_source'] = [ ]

# Avoid merging requests.
c['mergeRequests'] = lambda *_: False


####### BUILDERS

c['builders'] = []

# FACTORIES

m_annotator = annotator_factory.AnnotatorFactory(ActiveMaster)

def F_NACL_RECIPE():
  return m_annotator.BaseFactory(recipe='nacl',
      factory_properties = {'slavetype': 'Trybot'})

def F_NACLPORTS_RECIPE():
  return m_annotator.BaseFactory(recipe='nacl_ports',
      factory_properties = {'slavetype': 'Trybot'})

def CreateBot(password=config.Master.GetBotPassword(),
              builder_name=None,
              project=None,
              slave_names=None,
              factory_properties=None):
  """Generates and returns a builder along with its slave(s).

  Implicitly create slave_name or slave_names if they weren't created or
  specified.
  If none of slave_name or slave_names is supplied, a slave name will be
  constructed from the builder name.
  """
  # Don't enable auto_reboot for people testing locally.
  auto_reboot = ActiveMaster.is_production_host
  # Arm board slaves have issue rebooting continuously.
  if 'arm_hw_' in builder_name:
    auto_reboot = False
  if project in ['nacl', 'nacl-toolchain']:
    builder_factory = F_NACL_RECIPE()
  elif project == 'webports':
    builder_factory = F_NACLPORTS_RECIPE()
  else:
    assert False
  builddir = builder_name.replace(' ', '-')
  slavebuilddirs = {
      'nacl-toolchain-asan': 'nacl-asan',
      'nacl-toolchain-msan': 'nacl-msan',
      'nacl-toolchain-tsan': 'nacl-tsan',
      'nacl-toolchain-ubsan': 'nacl-ubsan',
  }
  if builder_name in slavebuilddirs:
    slavebuilddir = slavebuilddirs[builder_name]
  else:
    slavebuilddir = builddir
  builder = {
    'name': builder_name,
    'builddir': builddir,
    'slavebuilddir': slavebuilddir,
    'factory': builder_factory,
    'auto_reboot': auto_reboot,
  }
  if slave_names:
    builder['slavenames'] = slave_names
  else:
    builder['slavename'] = builder_name.replace(' ', '-')
  return builder


# Try queues.
pools = BuildersPools('nacl')


slaves_cfg = chromium_utils.ParsePythonCfg('slaves.cfg')
builder_categories = slaves_cfg['categories']
categories_to_slaves = slaves_cfg['categories_to_slaves']
categories_to_builders = slaves_cfg['categories_to_builders']


def GetSlaveNames(builder_name):
  return sum([categories_to_slaves[category]
      for category in builder_categories
      if builder_name in categories_to_builders[category]], [])

def GetAllBuilderNames():
  return list(set(sum(categories_to_builders.values(), [])))

all_builders = GetAllBuilderNames()
nacl_builders = [builder for builder in all_builders
    if builder.startswith('nacl-') and not builder.startswith('nacl-toolchain')]
nacl_toolchain_builders = [builder for builder in all_builders
    if builder.startswith('nacl-toolchain')]
webports_builders = [builder for builder in all_builders
    if builder.startswith('webports-')]

projects = {
    'nacl': nacl_builders,
    'nacl-toolchain': nacl_toolchain_builders,
    'webports': webports_builders,
}

for project in projects:
  for builder_name in projects[project]:
    slave_names = GetSlaveNames(builder_name)
    builder = CreateBot(builder_name = builder_name, project = project,
                        slave_names = slave_names)
    c['builders'].append(builder)
    pools[project].append(builder_name)


b_nacl_presubmit = {
  'name': 'nacl-presubmit',
  'slavebuilddir': 'nacl',
  'factory':
      m_annotator.BaseFactory('run_presubmit', {'repo_name': 'nacl'}),
  'slavenames': categories_to_slaves['precise64']
}
c['builders'].append(b_nacl_presubmit)

b_webports_presubmit = {
  'name': 'webports-presubmit',
  'slavebuilddir': 'webports',
  'factory':
      m_annotator.BaseFactory('run_presubmit', {
          'repo_name': 'webports',
          'runhooks': True
      }),
  'slavenames': categories_to_slaves['precise64']
}
c['builders'].append(b_webports_presubmit)

# Set "root" build property to "native_client" in all nacl-* builders,
# set it to "src" on all others.
for b in c['builders']:
  if b['name'].startswith('nacl-'):
    b.setdefault('properties', {})['root'] = 'native_client'
  else:
    b.setdefault('properties', {})['root'] = 'src'

####### BUILDSLAVES

# The 'slaves' list defines the set of allowable buildslaves. List all the
# slaves registered to a builder. Remove dupes.
c['slaves'] = master_utils.AutoSetupSlaves(c['builders'],
                                           config.Master.GetBotPassword())


####### SCHEDULERS

# Configure the Schedulers;
# Main Tryscheduler for the try queue. groups is defined in the loop above.
c['schedulers'] = []

code_review_sites = {
  'nacl': ActiveMaster.code_review_site,
  'nacl-toolchain': ActiveMaster.code_review_site,
  'webports': ActiveMaster.code_review_site,
}
c['schedulers'].append(TryJobHTTP(
    name='try_job_http',
    port=ActiveMaster.try_job_port,
    code_review_sites=code_review_sites,
    pools=pools))

for mode in ['opt_panda', 'perf_panda']:
  s = Triggerable(
      name='arm_%s_hw_tests' % mode,
      builderNames=['nacl-arm_hw_%s' % mode])
  c['schedulers'].append(s)


####### STATUS TARGETS

# Buildbot master url:
# Must come before AutoSetupMaster().
c['buildbotURL'] = ActiveMaster.buildbot_url

# Adds common status and tools to this master.
master_utils.AutoSetupMaster(c, ActiveMaster, False,
                             public_html='../master.chromium/public_html',
                             templates=['../master.client.nacl/templates'])

# Add more.

if MAIL_NOTIFIER:
  # Add a dumb MailNotifier first so it will be used for BuildSlave with
  # notify_on_missing set when they go missing.
  from buildbot.status import mail
  c['status'].append(mail.MailNotifier(
      fromaddr=ActiveMaster.from_address,
      builders=[],
      relayhost=config.Master.smtp,
      lookup=master_utils.UsersAreEmails()))

  # Try job result emails.
  from master.try_mail_notifier import TryMailNotifier
  c['status'].append(TryMailNotifier(
      fromaddr=ActiveMaster.from_address,
      reply_to=ActiveMaster.reply_to,
      subject="try of %(reason)s @ r%(revision)s %(timestamp)s",
      mode='all',
      relayhost=config.Master.smtp,
      lookup=master_utils.UsersAreEmails()))


# Keep last try jobs, the default is too low. Must keep at least a few days
# worth of try jobs.
c['buildHorizon'] = 2000
c['logHorizon'] = 2000
# Must be at least 2x the number of slaves.
c['eventHorizon'] = 100
# Must be at least 2x the number of on-going builds.
c['buildCacheSize'] = 100


####### PROJECT IDENTITY

# The 'projectURL' string will be used to provide a link
# from buildbot HTML pages to your project's home page.
c['projectURL'] = 'http://go/ChromeTryServer'
